<?php

/**
 * 模型基类
 * File Name：BaseModel.php
 * File Encoding：UTF-8
 * File New Time：2014-5-5 15:21:32
 * Author：水平凡
 * Mailbox：admin@abc3210.com
 */
class BaseModel extends CActiveRecord {

    //临时规则
    public $rules = false;
    // 数据库表达式
    protected $comparison = array('eq' => '=', 'neq' => '<>', 'gt' => '>', 'egt' => '>=', 'lt' => '<', 'elt' => '<=', 'notlike' => 'NOT LIKE', 'like' => 'LIKE', 'in' => 'IN', 'notin' => 'NOT IN');

    /**
     * 返回一条错误信息
     * @return string 错误信息
     */
    public function getOneError() {
        $error = $this->getErrors();
        if (!empty($error)) {
            $current = current($error);
            return $current[0];
        } else {
            return null;
        }
    }

    /**
     * 创建基于该规范中的规则验证的对象。
     * @return \CList
     * @throws CException
     */
    public function createValidators() {
        $validators = new CList;
        $rules = $this->rules ? $this->rules : $this->rules();
        foreach ($rules as $rule) {
            if (isset($rule[0], $rule[1]))  // attributes, validator name
                $validators->add(CValidator::createValidator($rule[1], $this, $rule[0], array_slice($rule, 2)));
            else
                throw new CException(Yii::t('yii', '{class} has an invalid validation rule. The rule must specify attributes to be validated and the validator name.', array('{class}' => get_class($this))));
        }
        return $validators;
    }

    /**
     * 设置临时规则
     * @param type $rules 规则，和rule()一样
     */
    public function setValidators($rules = false) {
        $this->rules = $rules;
    }

    /**
     * 使用ThinkPHP的查询表达式构造SQL语句的 Where部分并返回CDbCriteria对象
     * 使用手册：http://document.thinkphp.cn/manual_3_2.html#query_type
     * @param type $where
     * @param type $sqlStr 默认falsh，true只返回where语句不返回CDbCriteria对象
     * @return \CDbCriteria 返回CDbCriteria对象
     * @throws CException
     */
    public function where($where, $sqlStr = false) {
        //特殊处理
        $particular = array('select', 'distinct', 'params', 'limit', 'offset', 'order', 'group', 'join');
        $whereStr = '';
        //CDbCriteria
        $criteria = new CDbCriteria();
        if (is_array($where)) {
            $operate = isset($where['_logic']) ? strtoupper($where['_logic']) : '';
            if (in_array($operate, array('AND', 'OR', 'XOR'))) {
                // 定义逻辑运算规则 例如 OR XOR AND NOT
                $operate = ' ' . $operate . ' ';
                unset($where['_logic']);
            } else {
                // 默认进行 AND 运算
                $operate = ' AND ';
            }
            foreach ($where as $key => $val) {
                //检查是否在特殊处理中
                if (in_array($key, $particular)) {
                    try {
                        $criteria->$key = $val;
                    } catch (Exception $exc) {
                        
                    }
                    continue;
                }
                $whereStr .= '( ';
                // 查询字段的安全过滤
                if (!preg_match('/^[A-Z_\|\&\-.a-z0-9\(\)\,]+$/', trim($key))) {
                    throw new CException("表达式错误:{$key}");
                }
                // 多条件支持
                $multi = is_array($val) && isset($val['_multi']);
                $key = trim($key);
                if (strpos($key, '|')) { // 支持 name|title|nickname 方式定义查询字段
                    $array = explode('|', $key);
                    $str = array();
                    foreach ($array as $m => $k) {
                        $v = $multi ? $val[$m] : $val;
                        $str[] = '(' . $this->parseWhereItem($this->parseKey($k), $v) . ')';
                    }
                    $whereStr .= implode(' OR ', $str);
                } elseif (strpos($key, '&')) {
                    $array = explode('&', $key);
                    $str = array();
                    foreach ($array as $m => $k) {
                        $v = $multi ? $val[$m] : $val;
                        $str[] = '(' . $this->parseWhereItem($this->parseKey($k), $v) . ')';
                    }
                    $whereStr .= implode(' AND ', $str);
                } else {
                    $whereStr .= $this->parseWhereItem($this->parseKey($key), $val);
                }
                $whereStr .= ' )' . $operate;
            }
            //兼容最后一个条件满足
            $whereStr .= ' 1=1';
        } else {
            $whereStr = $where;
        }
        if (!$sqlStr) {
            $criteria->condition = $whereStr;
            return $criteria;
        } else {
            return $whereStr;
        }
    }

    // where子单元分析
    protected function parseWhereItem($key, $val) {
        $whereStr = '';
        if (is_array($val)) {
            if (is_string($val[0])) {
                if (preg_match('/^(EQ|NEQ|GT|EGT|LT|ELT)$/i', $val[0])) { // 比较运算
                    $whereStr .= $key . ' ' . $this->comparison[strtolower($val[0])] . ' ' . $this->parseValue($val[1]);
                } elseif (preg_match('/^(NOTLIKE|LIKE)$/i', $val[0])) {// 模糊查找
                    if (is_array($val[1])) {
                        $likeLogic = isset($val[2]) ? strtoupper($val[2]) : 'OR';
                        if (in_array($likeLogic, array('AND', 'OR', 'XOR'))) {
                            $likeStr = $this->comparison[strtolower($val[0])];
                            $like = array();
                            foreach ($val[1] as $item) {
                                $like[] = $key . ' ' . $likeStr . ' ' . $this->parseValue($item);
                            }
                            $whereStr .= '(' . implode(' ' . $likeLogic . ' ', $like) . ')';
                        }
                    } else {
                        $whereStr .= $key . ' ' . $this->comparison[strtolower($val[0])] . ' ' . $this->parseValue($val[1]);
                    }
                } elseif ('exp' == strtolower($val[0])) { // 使用表达式
                    $whereStr .= ' (' . $key . ' ' . $val[1] . ') ';
                } elseif (preg_match('/IN/i', $val[0])) { // IN 运算
                    if (isset($val[2]) && 'exp' == $val[2]) {
                        $whereStr .= $key . ' ' . strtoupper($val[0]) . ' ' . $val[1];
                    } else {
                        if (is_string($val[1])) {
                            $val[1] = explode(',', $val[1]);
                        }
                        $zone = implode(',', $this->parseValue($val[1]));
                        $whereStr .= $key . ' ' . strtoupper($val[0]) . ' (' . $zone . ')';
                    }
                } elseif (preg_match('/BETWEEN/i', $val[0])) { // BETWEEN运算
                    $data = is_string($val[1]) ? explode(',', $val[1]) : $val[1];
                    $whereStr .= ' (' . $key . ' ' . strtoupper($val[0]) . ' ' . $this->parseValue($data[0]) . ' AND ' . $this->parseValue($data[1]) . ' )';
                } else {
                    throw new CException(Yii::t('yii', '查询表达式错误：{express}.', array('{express}' => $val[0])));
                }
            } else {
                $count = count($val);
                $rule = isset($val[$count - 1]) ? strtoupper($val[$count - 1]) : '';
                if (in_array($rule, array('AND', 'OR', 'XOR'))) {
                    $count = $count - 1;
                } else {
                    $rule = 'AND';
                }
                for ($i = 0; $i < $count; $i++) {
                    $data = is_array($val[$i]) ? $val[$i][1] : $val[$i];
                    if ('exp' == strtolower($val[$i][0])) {
                        $whereStr .= '(' . $key . ' ' . $data . ') ' . $rule . ' ';
                    } else {
                        $whereStr .= '(' . $this->parseWhereItem($key, $val[$i]) . ') ' . $rule . ' ';
                    }
                }
                $whereStr = substr($whereStr, 0, -4);
            }
        } else {
            $whereStr .= $key . ' = ' . $this->parseValue($val);
        }
        return $whereStr;
    }

    /**
     * value分析
     * @access protected
     * @param mixed $value
     * @return string
     */
    protected function parseValue($value) {
        if (is_string($value)) {
            $value = '\'' . $this->escapeString($value) . '\'';
        } elseif (isset($value[0]) && is_string($value[0]) && strtolower($value[0]) == 'exp') {
            $value = $this->escapeString($value[1]);
        } elseif (is_array($value)) {
            $value = array_map(array($this, 'parseValue'), $value);
        } elseif (is_bool($value)) {
            $value = $value ? '1' : '0';
        } elseif (is_null($value)) {
            $value = 'null';
        }
        return $value;
    }

    /**
     * SQL指令安全过滤
     * @access public
     * @param string $str  SQL字符串
     * @return string
     */
    protected function escapeString($str) {
        return addslashes($str);
    }

    /**
     * 字段名分析
     * @access protected
     * @param string $key
     * @return string
     */
    protected function parseKey(&$key) {
        return $key;
    }

    protected function modelSetCache($key, $cache = true) {
        if (!$cache) {
            Yii::app()->cache->delete($key);
        }
        $return = Yii::app()->cache->get($key);
        return $return;
    }

    /**
     * model的值初始化,参数如果为空则把它所有的初始值给清空,如果有值,则把传过来的键清空
     * @param arr $arrData
     * @return [type] [description]
     */
    public function resetAttributes($arrData = '')
    {
        if($arrData)
        {
            foreach ($arrData as $item) 
            {
                $this->$item = null;
            }
        }else
        {
            $arrAttributes = array_keys( $this->attributes );
            if ( is_array( $arrAttributes ) && !empty( $arrAttributes ) )
            {
                foreach ( $arrAttributes as $item )
                {
                    $this->$item = null;
                }
            }
        }
    }

    /**
     * 便捷方式获取的CDbCriteria
     * @param  [type] $arrData [description]
     * @return [type]          [description]
     */
    public static function getC($arrData){
        $arrReturn = array();
        $arrReturn['condition'] = '1=1 ';
        foreach($arrData as $key => $strData){
            if(is_array($strData)){
                $sign = isset($strData['sign']) ? $strData['sign'] : ' =';
                $operation = isset($strData['operation']) ? $strData['operation'] : ' and';
                if($sign == 'in' || $sign == 'not in'){
                    $arrReturn['condition'] .= " {$operation} {$key} {$sign} ({$strData['data']})";  
                    //$arrReturn['params'][$key] = $strData['data'];                     
                }else{
                    $arrReturn['condition'] .= " {$operation} {$key} {$sign} :{$key}";  
                    $arrReturn['params'][$key] = $strData['data']; 
                }
            }else{
                if($key == 'order' || $key == 'limit' || $key == 'group'){
                    $arrReturn[$key] = $strData;
                    continue;
                }
                $arrReturn['condition'] .= " AND {$key} = :{$key}";  
                $arrReturn['params'][$key] = $strData;              
            }            
        }
        //echo $arrReturn['condition'];exit;
        return $objCDbCriteria = new CDbCriteria($arrReturn);        
    }

    /**
     * 把数组组合成格式  '1,2,3,4,5'这样的，让其适用于in的数据操作
     * @return [type] [description]
     */
    public static function getStrIn($arrData){
        $strResult = '';
        foreach ($arrData as $key => $value) {
            if($value != ''){
                $strResult .= ',' . $value;
            }
        }
        return substr($strResult, 1);
    }
     

}
